<template>
  <div style="height: 100vh;width: 100vw">
    <el-dropdown split-button size="mini" :disabled="isDelete" style="margin-right: 10px" @click="clickDraw">
      {{isDraw ? '结束绘制' : '开始绘制'}}{{drawTypeText}}
      <template #dropdown>
        <el-dropdown-menu>
          <el-dropdown-item @click.native="changeDrawType('plane')">飞机</el-dropdown-item>
          <el-dropdown-item @click.native="changeDrawType('ship')">舰船</el-dropdown-item>
        </el-dropdown-menu>
      </template>
    </el-dropdown>
    <el-button :disabled="!isDraw" size="mini" @click="clearDraw">清除绘制</el-button>
    <el-button size="mini" @click="getYaozi">腰子图</el-button>
    <el-button size="mini" :disabled="isDraw" @click="deleteDraw">{{isDelete ? '确认删除' : '删除轨迹'}}</el-button>
    <div id="map" class="map"></div>

    <div style="display: none">
      <div id="overPlay">
        <div class="overPlayText" v-if="hoverPointInfo.type == 'plane'">名称：飞燕一号</div>
        <div class="overPlayText" v-if="hoverPointInfo.type == 'ship'">名称：泰坦尼克号</div>
        <div class="overPlayText" v-if="hoverPointInfo.type == 'plane'">飞行速度：2.25马赫（2400公里/小时）</div>
        <div class="overPlayText" v-if="hoverPointInfo.type == 'ship'">航速：40节</div>
        <div class="overPlayText" v-if="hoverPointInfo.type == 'event'">在这拐了个弯</div>
      </div>
    </div>
  </div>
</template>

<script>
//加载ol自带样式
import Map from "ol/map";
import TileLayer from "ol/layer/tile";
import XYZ from "ol/source/xyz";
import View from "ol/view";
import Overlay from "ol/overlay";
import Feature from "ol/feature";
import Polygon from "ol/geom/polygon";
import Vector from "ol/layer/vector";
import VectorSource from "ol/source/vector";
import mapStyle from './js/mapStyle';
import Point from "ol/geom/point";
import LineString from "ol/geom/linestring";
import click from "ol/events/condition";
import Select from "ol/interaction/select";
import Sphere from "ol/sphere";
import * as PlotUtils from "../../../Utils/utils";


export default {
  data(){
    return {
      map: null,
      areaLayer: null,  //区域
      pointLayer: null, //点
      trailLayer: null,  //轨迹
      pointInfo: {},   //鼠标点击点信息
      hoverPointInfo: {},  //鼠标移入点信息
      drawLayer: null,   //绘图的轨迹
      pointTempLayer: null,  //绘制轨迹时添加的临时点
      isDraw: false,  //是否正在绘制
      isDelete: false, //是否在删除
      clickPoints: [],  //绘制时暂存的点
      tempLine: null,  //临时边
      tempPoint: null,  //临时点
      drawType: '',    //地图绘制类型
    }
  },
  computed: {
    drawTypeText(){
      let text = ''
      let map = {
        plane: '飞机',
        ship: '船舰',
      }
      if(this.drawType){
        text = map[this.drawType]
      }
      return (text ? ('(' + text + ')') : '')
    }
  },
  mounted() {
    this.initMap()

    setTimeout(() => {
      // //区域
      let data1 = [
        [130.403218, 10.92372],
        [138.403218, 8.92372],
        [140.403218, 15.92372],
        [135.403218, 16.92372],
      ]
      let data2 = [
        [160.403218, 24.92372],
        [165.403218, 29.92372],
        [164.403218, 32.92372],
        [160.403218, 27.92372],
      ]
      this.addArea([data1,data2])

      let data3 = [
        {
          id: 5,
          type: 'plane',
          coords: [177.403218, 27.92372],
        },
        {
          id: 6,
          type: 'plane',
          coords: [120.403218, 12.92372],
        },
      ]
      data3.forEach(e => {
        this.addPoint('plane',e)
      })

      let data4 = [
        {
          id: 7,
          type: 'ship',
          coords: [165.403218, 28.92372],
        },
        {
          id: 8,
          type: 'ship',
          coords: [138.403218, 14.92372],
        },
      ]
      data4.forEach(e => {
        this.addPoint('ship',e)
      })

      let data5 = [
        [
          [177.403218, 27.92372],
          [150.403218, 10.92372],
          [120.403218, 12.92372],
        ],
        [
          [165.403218, 28.92372],
          [138.403218, 14.92372],
        ]
      ]
      this.addTrail('red',data5)
      this.addPoint('red',{
        id: 10,
        type: 'event',
        coords: [150.403218, 10.92372],
      })
      // this.addHitArea(8000,1500)
    },2000)
  },
  methods: {
    //初始化地图
    initMap(){
      this.map = null
      this.layer = null
      this.pointLayer = null
      this.trailLayer = null
      // 图层
      this.layer = new TileLayer({
        source: new XYZ({
          visible: true,
          url: 'http://webrd01.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=2&scale=1&style=8',
          wrapX: true,
          crossOrigin: 'anonymous'
        }),
      })
      //区域
      this.areaLayer = new Vector({
        source: new VectorSource({
          wrapX: false,
        })
      })

      //点
      this.pointLayer = new Vector({
        source: new VectorSource(),
      })
      //轨迹
      this.trailLayer = new Vector({
        source: new VectorSource(),
      })
      //临时点
      this.pointTempLayer = new Vector({
        source: new VectorSource(),
      })

      let view = new View({
        projection: 'EPSG:4326',
        center: [135.403218, 30.92372],
        zoom: 4,
        maxZoom: 11,
        minZoom: 2,
        constrainResolution: true,  // 设置缩放级别为整数
        smoothResolutionConstraint: false,  // 关闭无级缩放地图
      })
      // 自定义约束函数，只限制Y轴（垂直方向）
      // 自定义约束函数
      view.constrainCenter = (center) => {
        this.mapSize = this.map.getSize();

        // 设置边界限制（经纬度）
        let maxLat = 85;  // 最大纬度
        let minLat = -85; // 最小纬度

        // 转换为墨卡托坐标
        let maxY = maxLat;
        let minY = minLat;

        // 获取当前视图范围
        let extent = view.calculateExtent(this.mapSize);
        let height = extent[3] - extent[1];

        // 计算允许的最小/最大中心点Y坐标
        let maxCenterY = maxY - height/2;
        let minCenterY = minY + height/2;

        // 只约束Y坐标，X坐标保持不变
        return [
          center[0], // X坐标不变
          Math.max(minCenterY, Math.min(maxCenterY, center[1])) // 约束Y坐标
        ];
      }


      // 初始化地图到指定DOM元素
      this.map = new Map({
        layers: [this.layer, this.trailLayer, this.areaLayer,  this.pointLayer, this.pointTempLayer],
        target: "map",
        view
      })

      let selectInteraction = new Select({
        layers: [this.pointLayer],
      });
      this.map.addInteraction(selectInteraction)
      selectInteraction.on('select', e => {
        const selectedFeature = (e.selected || [])[0];
        if(selectedFeature){
          this.pointInfo = selectedFeature.getProperties()
          console.log(this.pointInfo)
        }
      })

      let hoverFeature = null
      this.map.on('pointermove',(e) => {
        let feature = this.map.forEachFeatureAtPixel(e.pixel, (feature, layer) => {
          return feature
        },{hitTolerance: 5})
        //有feature且feature变化才执行
        if(feature != hoverFeature){
          hoverFeature = feature
          if(feature && feature.getGeometry().getType() == 'Point'){
            this.map.getTargetElement().style.cursor = "pointer";
            this.hoverPointInfo = feature.getProperties()
            this.addOverlay(this.hoverPointInfo.coords,'overPlay')
          }else{
            this.map.getTargetElement().style.cursor = "";
            this.hoverPointInfo = {}
            this.removeOverlays()
          }
        }
      })

    },
    getYaozi(){
      let pnts = [
          [132.403218, 47.92372],
          [127.403218, 50.92372],
          [120.403218, 49.92372],
          [125.403218, 48.92372],
      ]
      pnts.push(pnts[0], pnts[1])
      let [normals, pList] = [[], []]
      for (let i = 0; i < pnts.length - 2; i++) {
        let normalPoints = PlotUtils.getBisectorNormals(0.3, pnts[i], pnts[i + 1], pnts[i + 2])
        normals = normals.concat(normalPoints)
      }
      let count = normals.length
      normals = [normals[count - 1]].concat(normals.slice(0, count - 1))
      console.log(normals,'normals')
      for (let i = 0; i < pnts.length - 2; i++) {
        let pnt1 = pnts[i]
        let pnt2 = pnts[i + 1]
        pList.push(pnt1)
        for (let t = 0; t <= 100; t++) {
          let pnt = PlotUtils.getCubicValue(t / 100, pnt1, normals[i * 2], normals[i * 2 + 1], pnt2)
          pList.push(pnt)
        }
        pList.push(pnt2)
      }
      this.addArea([pList])
      pnts.forEach(e => {
        this.addPoint('red', {
          type: 'red',
          coords: e,
          groupId: 'point-' + Date.now()
        })
      })
    },

    //打击范围
    addHitArea(){
      let radius1 = 6000
      let center = [122, 46]
      let wgs84Sphere = new Sphere(6371008.8)
      let points1 = []

      for (let angle = 0; angle < 360; angle += 10){
        const point = wgs84Sphere.offset(center,radius1 * 1000,(angle * Math.PI) / 180)
        points1.push(point)
      }
      points1 = this.letHitTop(center,points1)
      const polygon = new Polygon([points1])
      const feature = new Feature(polygon)
      feature.setStyle(mapStyle.redAreaStyle)
      this.areaLayer.getSource().addFeature(feature)
      this.addPoint('red',
      {
        id: 10,
        type: 'red',
        coords: center,
      },)
    },
    letHitTop(center,points){
      let point0,point1
      if(center[1] >= 0){
        point0 = points[0]
        point1 = points[1]
      }
      if(center[1] < 0){
        point0 = points[18]
        point1 = points[17]
      }
      let xielv = (point0[0] - point1[0]) / (point0[1] - point1[1])
      if(center[1] > 0 && xielv > 0){
        let jd = (85 - point0[1]) * xielv
        let hitWidth = (point0[0] - center[0] + jd) * 2
        points = [[jd + point0[0],85], ...points, [jd + point0[0] - hitWidth,85]]
      }
      if(center[1] < 0 && xielv < 0){
        let jd = (-85 - point0[1]) * xielv
        let hitWidth = (point0[0] - center[0] + jd) * 2
        let list1 = points.slice(0,19)
        let list2 = points.slice(19,36)
        let list = [...list1,[jd + point0[0], -85],[jd + point0[0] - hitWidth,-85],...list2]
        points = list
      }
      return points
    },

    //地图上加区域
    addArea(data){
      console.log(data,'data')
      let feature = new Feature({
        geometry: new Polygon(data),
      })
      feature.setStyle(mapStyle.redAreaStyle)
      this.areaLayer.getSource().addFeature(feature)
    },
    normalizeCoordinate(coord) {
      console.log(coord)
      if(!coord) return
      let lon = coord[0];
      let lat = coord[1];

      // 规范化经度
      lon = lon % 360;
      if (lon < 0) lon += 360;
      if (lon >= 180) lon -= 360;

      return [lon, lat];
    },
    //地图上加点
    addPoint(type, data){
      let point = new Point(this.normalizeCoordinate(data.coords))
      if(type == 'plane'){
        let pointFeature = new Feature({
          geometry: point,
          ...data
        })
        pointFeature.setStyle(mapStyle.pointRedPlane)
        this.pointLayer.getSource().addFeature(pointFeature)
      }
      if(type == 'ship'){
        let pointFeature = new Feature({
          geometry: point,
          ...data
        })
        pointFeature.setStyle(mapStyle.pointRedShip)
        this.pointLayer.getSource().addFeature(pointFeature)
      }
      if(type == 'red'){
        let pointFeature = new Feature({
          geometry: point,
          ...data
        })
        pointFeature.setStyle(mapStyle.pointRed)
        this.pointLayer.getSource().addFeature(pointFeature)
      }

    },
    //地图上加轨迹
    addTrail(type,data){
      data.forEach(e => {
        let feature = new Feature({
          geometry: new LineString(e),
        })
        feature.setStyle(mapStyle.redLineArrow(feature))
        this.trailLayer.getSource().addFeature(feature)
      })
    },
    //地图上加div
    addOverlay(data,id){
      if(!this.map.getOverlayById(id)){
        let marker = new Overlay({
          id,
          position: data,
          element: document.getElementById(id),
          offset: [10, 20]
        });
        this.map.addOverlay(marker);
        marker.setPositioning("top-left");
      } else{
        let marker = this.map.getOverlayById(id)
        marker.setPosition(data)
      }
    },
    //地图上删除div
    removeOverlays() {
      let overlays = this.map.getOverlays();
      for (let i = 0, len = overlays.getLength(); i < len; i++) {
        overlays.item(i).setPosition(undefined)
      }
    },

    //修改绘制类型
    changeDrawType(type){
      this.drawType = type
    },
    //开始绘制地图
    clickDraw(){
      if(this.isDraw){
        this.endDraw()
      }else{
        if (!this.drawType) {
          this.$message.warning('请选择绘制类型')
          return
        }
        this.drawTrail()
      }
    },
    //进入开始手动绘制状态
    drawTrail(){
      if(!this.isDraw){
        this.isDraw = true
        this.clickPoints = []
        this.map.on('click', this.handleMapClick)
      }
    },
    //结束手动绘制状态
    endDraw(){
      if(this.isDraw){
        this.isDraw = false
        this.map.un('click', this.handleMapClick)
        //唯一标识,便于统一管理
        let groupId = 'point-' + Date.now()
        //临时点改为真实点
        if(this.clickPoints){
          this.pointTempLayer.getSource().clear()
          this.tempPoint = null
          this.clickPoints.forEach((e, index) => {
            if(index == 0 || index == (this.clickPoints.length - 1)){
              this.addPoint(this.drawType, {
                type: this.drawType,
                coords: e,
                groupId
              })
            }
          })
        }
        //临时线改为真实线
        if(this.clickPoints.length >= 2){
          let feature = new Feature({
            geometry: new LineString(this.clickPoints),
            groupId
          })
          feature.setStyle(mapStyle.redLineArrow(feature))
          this.trailLayer.getSource().addFeature(feature)
          if(this.tempLine){
            this.trailLayer.getSource().removeFeature(this.tempLine)
            this.tempLine = null
          }
          this.clickPoints = []
        }
      }
    },
    //绘制的点击事件
    handleMapClick(e){
      if(!this.isDraw) return;
      const coord = e.coordinate
      this.clickPoints.push(coord)

      if(this.tempLine){
        this.trailLayer.getSource().removeFeature(this.tempLine)
      }
      if(this.clickPoints.length >= 2){
        this.tempLine = new Feature({
          geometry: new LineString(this.clickPoints),
        })
        this.tempLine.setStyle(mapStyle.tempLineArrow(this.tempLine))
        this.trailLayer.getSource().addFeature(this.tempLine)
      }
      if(coord){
        this.tempPoint = new Feature({
          geometry: new Point(coord)
        })
        this.tempPoint.setStyle(mapStyle.positionPointTemp)
        this.pointTempLayer.getSource().addFeature(this.tempPoint)
      }

    },
    //清除绘制
    clearDraw(){
      this.pointTempLayer.getSource().clear()
      this.tempPoint = null
      if(this.tempLine){
        this.trailLayer.getSource().removeFeature(this.tempLine)
        this.tempLine = null
      }
      this.clickPoints = []
    },
    //删除轨迹
    deleteDraw(){
      this.isDelete = !this.isDelete
      if(this.isDelete){
        this.map.on('click',this.handleMapDelete)
      }else{
        this.map.un('click',this.handleMapDelete)
      }
    },
    handleMapDelete(e){
      let feature = this.map.forEachFeatureAtPixel(e.pixel, (feature, layer) => {
        return feature
      },{hitTolerance: 5})
      if(!feature.get('groupId')){
        this.$message.warning('该轨迹非手绘轨迹,不可删除')
        return
      }
      const pointFeatures = this.pointLayer.getSource().getFeatures()
      pointFeatures.forEach(f => {
        if(f.get('groupId') == feature.get('groupId')){
          this.pointLayer.getSource().removeFeature(f)
        }
      })
      const lineFeatures = this.trailLayer.getSource().getFeatures()
      lineFeatures.forEach(f => {
        if(f.get('groupId') == feature.get('groupId')){
          this.trailLayer.getSource().removeFeature(f)
        }
      })
    },
  }
}
</script>

<style scoped>
#map{
  height: calc(100% - 80px);
  width: 100%;
}
#overPlay{
  padding:  5px 10px;
  background-color: rgba(8, 10, 16, 0.6);
}
.overPlayText{
  font-size: 12px;
  color: white;
  max-width: 200px;
}
</style>